#include "ThreadPool.h"
#include "Exception.h"
SK


ThreadPool::ThreadPool (u32 numThreads)
: numThreads(numThreads), poolManager (NULL)
{
    initThreads ();
}

ThreadPool::~ThreadPool ()
{
    threadLock.lock();
    for (u32 i=0; i<numThreads; i++)
    {
        delete threads [i];
    }
    delete threadCompEvents;

    threadLock.unlock();

    if (poolManager)
        delete poolManager;

}

void ThreadPool::initThreads (void)
{
    threads = new pThread [this->numThreads];
    threadCompEvents = new EventList (this->numThreads, true);

    for (u32 i=0; i<numThreads; i++)
        threads [i] = new Thread (threadCompEvents->getEvent (i));
}

void ThreadPool::queueTask (Task *task)
{
    ScopedLock s (&this->taskLock);
    tasks.push(task);
}


Task* ThreadPool::getNextTask (void)
{
    ScopedLock s (&this->taskLock);

    Task *tmp;
    if (tasks.size () > 0)
    {
        tmp = tasks.front();
        tasks.pop();
    }
    else
        tmp = NULL;

    return tmp;
}

Thread *ThreadPool::getFreeThread (void)
{
    //ScopedLock s (&this->threadLock);
    int id = threadCompEvents->waitForAny ();

    if (id == -1)
        return NULL;
    else
    {
        threadCompEvents->reset (id);
        return threads [id];
    }
}


void ThreadPool::run(void)
{
    while (true)
    {
        Task *tsk = getNextTask ();
        if (!tsk)
        {
            Sleep (10);
            continue;
        }

        //We have a task, now find a thread
        Thread *t;
        t = this->getFreeThread ();

        if (t == NULL)
            throw new Exception ("Failed to find an empty thread.");

        t->start (tsk);

    }
}

void ThreadPool::start (void)
{
	this->poolManager = new Thread ((THREAD_START_PROC)&ThreadPool::_poolStart, static_cast <void *>(this));
    this->poolManager->start(NULL);
}

void ThreadPool::_poolStart (void *pool)
{
    ThreadPool *p = static_cast <ThreadPool *>(pool);
    p->run ();
}

EK